package ch7.DiningPhilosophers;

import util.Debug;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class DeadlockDetector extends Thread{
    static final ThreadMXBean tmb = ManagementFactory.getThreadMXBean();

    /**
     * 检测周期（单位：毫秒）
     */
    private final long monitorInterval;

    public DeadlockDetector(long monitorInterval) {
        this.monitorInterval = monitorInterval;
    }

    public DeadlockDetector() {
        this(200);
    }

    public static ThreadInfo[] findDeadlockedThreads() {
       long[] ids = tmb.findDeadlockedThreads();
       return null ==tmb.findDeadlockedThreads() ? new ThreadInfo[0] : tmb.getThreadInfo(ids);
    }

    public static Thread findThreadById(long threadId) {
        for (Thread thread : Thread.getAllStackTraces().keySet()) {
            if (thread.getId() == threadId) {
                return thread;
            }
        }
        return null;
    }

    /**
     * 根据线程的id，向该线程发送中断信号
     * @param threadID
     * @return
     */
    public static boolean interruptThread(long threadID) {
        Thread thread = findThreadById(threadID);
        if (null != thread) {
            thread.interrupt();
            return true;
        }
        return false;
    }

    @Override
    public void run() {
        ThreadInfo[] threadInfoList;
        ThreadInfo ti;
        int i = 0;
        try {
            for (;;) {
                // 检测系统中是否存在死锁的线程
                threadInfoList = DeadlockDetector.findDeadlockedThreads();
                if (threadInfoList.length > 0) {
                    // 任意选取一个死锁的线程
                    ti = threadInfoList[i++ % threadInfoList.length];
                    Debug.error("Deadlock detected, trying to recover" + " by interrupting %n thread(%d,%s)%n",
                            ti.getThreadId(), ti.getThreadName());
                    // 给选中的线程发送中断信号
                    DeadlockDetector.interruptThread(ti.getThreadId());
                    continue;
                } else {
                    Debug.info("No Deadlock found!");
                    i = 0;
                } // for循环结束
                Thread.sleep(monitorInterval);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
